#region File Description
//-----------------------------------------------------------------------------
// Primitives3DGame.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SilverlightViewport;
using SilverlightViewport.XNA;

#endregion

namespace Primitives3D
{
    /// <summary>
    /// This sample shows how to draw 3D geometric primitives
    /// such as cubes, spheres, and cylinders.
    /// </summary>
    public class Primitives3DGame : Microsoft.Xna.Framework.Game
    {
        #region Fields

        GraphicsDeviceManager graphics;

        SpriteBatch spriteBatch;
        SpriteFont spriteFont;

        KeyboardState currentKeyboardState;
        KeyboardState lastKeyboardState;
        GamePadState currentGamePadState;
        GamePadState lastGamePadState;


        // Store a list of primitive models, plus which one is currently selected.
        List<GeometricPrimitive> primitives = new List<GeometricPrimitive>();

        int currentPrimitiveIndex = 0;


        // Store a list of tint colors, plus which one is currently selected.
        List<Color> colors = new List<Color>
        {
            Color.White,
            Color.Red,
            Color.Green,
            Color.Blue,
            Color.Black,
        };

        int currentColorIndex = 0;


        // Are we rendering in wireframe mode?
        bool isWireframe;

		XnaSilverlightComponent _silverlight;
		private Vector2 Size = new Vector2(640, 480);

        #endregion

        #region Initialization


        public Primitives3DGame()
        {
            Content.RootDirectory = "Content";

            graphics = new GraphicsDeviceManager(this);

            graphics.PreferredBackBufferWidth = 1024;
            graphics.PreferredBackBufferHeight = 768;

			_silverlight = new XnaSilverlightComponent(this);
			_silverlight.Size = Size;
			_silverlight.BaseUrl = "http://silverlight.net/";
			_silverlight.Source = "http://silverlight.net/clientBin/showcasenav/ShowcaseNav.xap";
        }

		protected override void Initialize()
		{
			base.Initialize();
			_silverlight.Initialize();
		}

        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            spriteFont = Content.Load<SpriteFont>("Arial");

            primitives.Add(new CubePrimitive(GraphicsDevice, 1.6f));
			//primitives.Add(new SpherePrimitive(GraphicsDevice));
			//primitives.Add(new CylinderPrimitive(GraphicsDevice));
			//primitives.Add(new TorusPrimitive(GraphicsDevice));
			//primitives.Add(new TeapotPrimitive(GraphicsDevice));
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Allows the game to run logic.
        /// </summary>
        protected override void Update(GameTime gameTime)
        {
			_silverlight.Update(gameTime);

            HandleInput();

            base.Update(gameTime);
        }


        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // Set renderstates for either wireframe or solid drawing.
            RenderState renderState = GraphicsDevice.RenderState;

            if (isWireframe)
            {
                renderState.FillMode = FillMode.WireFrame;
                renderState.CullMode = CullMode.None;
            }
            else
            {
                renderState.FillMode = FillMode.Solid;
                renderState.CullMode = CullMode.CullCounterClockwiseFace;
            }

            // Create camera matrices, making the object spin.
            float time = (float)gameTime.TotalGameTime.TotalSeconds;

            float yaw = time * 0.4f;
            float pitch = time * 0.7f;
            float roll = time * 1.1f;

            Vector3 cameraPosition = new Vector3(0, 0, 2.5f);

            float aspect = GraphicsDevice.Viewport.AspectRatio;

            Matrix world = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll);
            Matrix view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
            Matrix projection = Matrix.CreatePerspectiveFieldOfView(1, aspect, 1, 10);

            // Draw the current primitive.
            GeometricPrimitive currentPrimitive = primitives[currentPrimitiveIndex];
            Color color = colors[currentColorIndex];

            currentPrimitive.Draw(_silverlight.Texture, world, view, projection, color);

            // Reset the fill mode renderstate.
            GraphicsDevice.RenderState.FillMode = FillMode.Solid;

            // Draw overlay text.
            string text = "A = change primitive\n" +
                          "B = change color\n" +
                          "Y = toggle wireframe";

            spriteBatch.Begin();
            spriteBatch.DrawString(spriteFont, text, new Vector2(86, 48), Color.White);
            spriteBatch.End();

            //base.Draw(gameTime);
        }


        #endregion

        #region Handle Input


        /// <summary>
        /// Handles input for quitting or changing settings.
        /// </summary>
        void HandleInput()
        {
            lastKeyboardState = currentKeyboardState;
            lastGamePadState = currentGamePadState;

            currentKeyboardState = Keyboard.GetState();
            currentGamePadState = GamePad.GetState(PlayerIndex.One);

            // Check for exit.
            if (IsPressed(Keys.Escape, Buttons.Back))
            {
                Exit();
            }

            // Change primitive?
            if (IsPressed(Keys.A, Buttons.A))
            {
                currentPrimitiveIndex = (currentPrimitiveIndex + 1) % primitives.Count;
            }

            // Change color?
            if (IsPressed(Keys.B, Buttons.B))
            {
                currentColorIndex = (currentColorIndex + 1) % colors.Count;
            }
            
            // Toggle wireframe?
            if (IsPressed(Keys.Y, Buttons.Y))
            {
                isWireframe = !isWireframe;
            }
        }


        /// <summary>
        /// Checks whether the specified key or button has been pressed.
        /// </summary>
        bool IsPressed(Keys key, Buttons button)
        {
            return (currentKeyboardState.IsKeyDown(key) &&
                    lastKeyboardState.IsKeyUp(key)) ||
                   (currentGamePadState.IsButtonDown(button) &&
                    lastGamePadState.IsButtonUp(button));
        }


        #endregion
    }


    #region Entry Point

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static class Program
    {
		[STAThread]
        static void Main()
        {
            using (Primitives3DGame game = new Primitives3DGame())
            {
                game.Run();
            }
        }
    }

    #endregion
}
